<html>

<head>
<meta http-equiv="Content-Language" content="en-us">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 6.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>The Meta programming language</title>
</head>

<body>

<h1>The Meta Macro Processor</h1>
<p>Ian Horswill, Northwestern University, February 2003</p>
<p>[<i>This probably isn't accurate anymore, but it won't be outrageously out of 
date </i>- idh 12/17/2004]</p>
<h2>Background</h2>
<p>The macro processor is a language (of sorts) that started as a scheme-&gt;C# translator and
morphed into a kind of macro processor for C#.&nbsp; The original intention was
to use it to bootstrap a LISP-like scripting language for .NET that would be
used for an introductory programming curriculum for students in the arts and
humanities.&nbsp; It quickly became obvious that that was a bad idea, since
writing even a moderately efficient LISP implementation in .NET really required
direct access to the non-LISP features of .NET.&nbsp; At that point, it became a 
glorified macro processor for C# that I just used to write an interpreter for 
the real langauge (Meta).&nbsp; However, the comments in the source code for the 
macro processor still refer to the macro processor as &quot;meta&quot; since once they 
were the same language.</p>
<p>The macro processor gives the programmer a way of writing pigeon C# in LISP-like prefix
notation (i.e. parentheses instead of curly braces and infix operators).&nbsp;
Although it might seem like an odd thing to do, it's useful because (1) it lets
you write Common-Lisp-style macros (sorry, no Scheme hygienic macros), which
both saves time and lets you defer decisions about how certain kinds of things
will be compiled or represented them by hiding them inside the code for the
macros, and (2) it saves you having to write most but not all of the type
declarations since the compiler does reasonably good type inference.</p>
<h2>Caveats</h2>
<p>As of this writing, the macro processor is just smart enough to do the things I
need it to do an no smarter.&nbsp; I have not done any real development on it 
for a year or two.&nbsp; It is <b>not</b> industrial strength.&nbsp;
In particular, there are a lot of places where the semantics of C# show through
into the macro language semantics where they shouldn't.&nbsp; For example, C# will let you
shadow a global variable with a local variable of the same name, but it won't
let you shadow a local variable of the same name, even if the shadowing variable
is carefully enclosed in its own scope by curly braces.&nbsp; That's a pain for
writing macros because it means you have to gensym local variable names.&nbsp;
At some point, I should really hack the compiler to rename the enclosed
variables, or better yet, do real hygienic macros.&nbsp; But since the compiler
is only a bootstrapping tool, not a goal in itself, I'm only adding features
when I really need them to build the arts stuff.&nbsp; </p>
<h2>What you can't do in the macro language</h2>
<p>There are a bunch of C# things you can't do in the macro language:</p>
<ul>
  <li><b>No overloading</b><br>
    Sorry.&nbsp; It makes type inference too difficult.&nbsp; There are some
    tricks you can pull, however, to call existing .NET code that has overloaded
    types.&nbsp; See the section on importing code.</li>
  <li><b>Two classes can't have members of the same name</b><br>
    Same reason.&nbsp; Yea, this really sucks.&nbsp; Hey, whaddya want?&nbsp;
    The world?</li>
  <li><b>No structs<br>
    No explicitly defined constructors</b><br>
    Although these would be easy to add.</li>
  <li><b>No delegates or events</b><br>
    This is only a problem if you want to define a new kind of delegate or
    event.&nbsp; Since delegates get created with <code>new</code>, as if they
    were objects, you can use predefined delegate types by lying to the compiler
    and telling it they're classes.</li>
  <li><b>No interfaces</b><br>
    At least you can't declare something to be of an interface type.&nbsp;
    Again, it's easy to use existing classes of existing interface types.</li>
  <li><b>No multidimensional arrays</b></li>
  <li><b>No user-defined properties</b></li>
  <li><b>No attributes</b></li>
</ul>
<p>There are also a bunch of LISP things you can't do in the macro language:</p>
<ul>
  <li><b>No higher-order procedures</b><br>
    There's no procedure data type and we don't support delegates.</li>
  <li><b>Types aren't really first-class</b><br>
    So you can't say <code>(new t)</code> where <code>t</code> is a local
    variable.&nbsp; It's got to be a real type name.</li>
  <li><b>Weird expression/statement restrictions</b><br>
    You can't have a let, for, while, or begin expression in the test of a while
    or for loop.&nbsp; There's no good way of transmogrifying that into C# code.</li>
</ul>
<h2>Program structure</h2>
<p>You compile code using the <code>define-module</code> macro:</p>
<blockquote>
  <p><code>(define </code><i>project</i><code> (make-project &quot;</code><i>directory</i><code>&quot;
  &quot;</code><i>namespace</i><code>&quot;))<br>
  <br>
  (define-module (</code><i>project&nbsp; module-name</i><code>)<br>
  &nbsp; </code><i>class-definitions</i> ...<code>)</code></p>
</blockquote>
<p><code>Define-module</code> requires a project object, which specifies the
directory to put the object code in and the .NET namespace into which the code
should be compiled.&nbsp; The <i>module-name</i> determines the name of the <code>.cs</code>
file that the module will be compiled into.&nbsp; Projects can have many
modules, of course.</p>
<h2>Class definitions</h2>
<p>New user classes are defined using <code>define-class</code>:</p>
<blockquote>
  <p><code>(define-class (</code><i>class</i><code> (</code><i>type&nbsp; field</i><code>)
  </code>...<code>) </code><i>parent-class</i><br>
  <code>&nbsp; (define </code><i>new-field</i><code> (</code><i>keywords </i>...&nbsp;
  <i>type</i><code>) </code><i>value</i><code>)</code> ...<br>
  <code>&nbsp; (define </code><i>shadowed-field</i><code> </code><i>value</i><code>)</code>
  ...<br>
  <code>&nbsp; (define (</code><i>new-method&nbsp; thisarg</i><code> (</code><i>type&nbsp;
  arg</i><code>) </code>...<code>) (</code><i>keywords </i>...&nbsp; <i>return-type</i><code>)<br>
  &nbsp;&nbsp;&nbsp; </code><i>body </i>...<code>)<br>
  &nbsp; </code>...<code><br>
  &nbsp; (define (</code><i>shadowed-method&nbsp; thisarg</i><code> (</code><i>type&nbsp;
  arg</i><code>) </code>...<code>)<br>
  &nbsp;&nbsp;&nbsp; </code><i>body </i>...<code>)<br>
  &nbsp; </code>...<code>)</code></p>
</blockquote>
<p>Defines a new class, <i>class</i>&nbsp; with the specfied <i>field</i>s and <i>method</i>s.</p>
<ul>
  <li>Fields that are declared in the first line take their initial values from
    constructor arguments, other fields from the expressions given in their
    declarations.</li>
  <li>Keywords may be any of the standard ones: <code>static</code>, <code>virtual</code>,
    etc.&nbsp; These keywords should only be specified for the class that
    originally defines them.&nbsp; When child classes define alternate
    (shadowed) versions of them, the compiler will use whatever keywords and
    type were provided in the original definition.</li>
</ul>
<p>The class will be bound to a global variable of the same name that can be
used as a constructor for the class (hence the procedure-definition-like syntax)
or used with the <code>new</code>, <code>new-array</code>, <code>is?</code>, <code>the</code>,
or <code>cast</code> operators.</p>
<p><b>Caveats:</b></p>
<ul>
  <li>The members will also be bound to <b>global </b>variables.&nbsp; So you
    can run into trouble if you try to have two unrelated classes with members
    of the same name.</li>
  <li>There's no nice way to embed the object<code>.</code>member notation in
    infix notation, so class members are accessed very differently in the macro 
	language than
    in C#.&nbsp;&nbsp; (Almost) all class members are accessed as if there were
    procedures.&nbsp; Fields look like procedures of one argument, the object to
    which they belong.&nbsp; <i>N</i>-argument methods look like <i>n+1</i>-argument
    procedures, where the first argument is the object on which they are
    called.&nbsp; The only exceptions are static fields, which are accessed as
    global variables.</li>
  <li>Even methods of a class have to access the class's members as if they were
    procedures.</li>
</ul>
<p>Abstract classes are defined by saying:</p>
<blockquote>
  <p><code>(define-class </code><i>class </i> <i>parent-class</i> ...<code>)</code></p>
</blockquote>
<p>that is, by giving them no prototype for the constructor.</p>
<h2>Expression types</h2>
<ul>
  <li>Standard LISP'y stuff: <code>if</code>, <code>cond</code>, <code>let</code>,
    <code>begin</code><br>
    As in Scheme</li>
  <li><code>(set </code><i>settable</i>&nbsp; <i>value</i>)<br>
    Same as <code>setf</code> in Common Lisp.&nbsp; Changes <i>settable</i> to <i>value</i>.&nbsp;
    <i>Settable</i> may be a variable or a property.&nbsp; Note that when <i>settable
    </i>is a complex expression, it trusts you that the thing you're trying to
    change is a property and blindly translates it into C# code.</li>
  <li><code>(while </code><i>condition<br>
    &nbsp;&nbsp;&nbsp; body </i>...<code>)</code><br>
    Standard while loop.&nbsp; However, it compiles to a C# <code>while</code>
    statement, and statements can't be embedded in other expressions.&nbsp; So
    its type is always <code>void</code>.</li>
  <li><code>(for ((</code><i>var&nbsp; init&nbsp; next</i><code>) </code>...<code>)<br>
    &nbsp;&nbsp;&nbsp;&nbsp; </code><i>condition<br>
    &nbsp;&nbsp;&nbsp;&nbsp; body </i>...<code>)</code><br>
    An almost standard lisp do loop.&nbsp; However, it compiles to a C# <code>for</code>
    statement, and statements can't be embedded in other expressions.&nbsp; So
    its type is always <code>void</code>.&nbsp; Also, the <i>condition</i> tests
    whether to continue, not whether to terminate.</li>
  <li><code>(dotimes (</code><i>var&nbsp; count</i><code>) </code><i>body </i>...<code>)&nbsp;&nbsp;&nbsp;&nbsp;
    </code><b>macro</b><br>
    As in Common Lisp.</li>
  <li><code>(do-array (</code><i>var&nbsp; array</i><code>) </code><i>body </i>...<code>)&nbsp;&nbsp;&nbsp;&nbsp;
    </code><b>macro</b><br>
    Like the Common Lisp dolist, but for arrays.</li>
  <li><code>(map-array (</code><i>var&nbsp; array&nbsp; result-element-type</i><code>)
    </code><i>body </i>...<code>)&nbsp;&nbsp;&nbsp; </code><b>macro</b><br>
    Like doarray, but collects the results of <i>body</i> into a new
    array.&nbsp; The <i>result-element-type</i> is optional and defaults to <code>object</code>.</li>
  <li><code>(inc </code><i>settable</i><code>)<br>
    (dec </code><i>settable</i><code>)</code><br>
    Shorthand for incrementing/decrementing.&nbsp; Like Common Lisp <code>incf</code>/<code>decf</code>.</li>
  <li><code>(when </code><i>condition&nbsp; body </i>...<code>)<br>
    (unless </code><i>condition&nbsp; body </i>...<code>)</code><br>
    As in Common Lisp.</li>
</ul>
<h2>User-defined operators</h2>
<ul>
  <li><code>(</code><i>class&nbsp; constructor-args </i>...<code>)</code><br>
    Just an alternate syntax for <code>new</code>.</li>
  <li><code>(</code><i>field&nbsp; object</i><code>)</code><br>
    Returns <i>object</i><code>.</code><i>field</i>.</li>
  <li><code>(</code><i>method&nbsp; object&nbsp; args</i><code> </code>...<code>)</code><br>
    Returns <i>object</i><code>.</code><i>method</i><code>(</code><i>args</i><code>,
    </code>...<code>)</code>.</li>
</ul>
<h2>Built-in operators</h2>
<ul>
  <li>+, <code>-</code>, <code>*</code>, <code>/</code>, etc.<br>
    If I'm missing one, let me know.</li>
  <li><code>eq?</code>, <code>=</code><br>
    These <b>both</b> compile to the C# <code>==</code> operator, which compiles
    to a call on the .NET <code>equals()</code> method.&nbsp; Their semantics
    are therefore somewhat ill-defined, since you can define <code>equals()</code>
    any way you want.</li>
  <li><code>Vector-ref</code>, <code>string-ref</code>, etc.<br>
    Sorry.&nbsp; You need to give these separate names in order to help type
    inference along.</li>
  <li><code>(length </code><i>object</i><code>)</code><br>
    Returns the number of elements in object, at least if it's an array, string,
    etc.&nbsp; Note this is a place where the lack of support for overloading
    means we have to pretend a lot of overloaded methods are really one very
    generic procedure.&nbsp; So if you call length on something that you can't
    call length on, the macro processor won't notice and you'll get a type error
    from the C# compiler.</li>
  <li><code>(is? </code><i>object class</i><code>)</code><br>
    The C# is operator.</li>
  <li><code>(the </code><i>type object</i><code>)<br>
    </code>A compile-time declaration that <i>object</i> is of class <i>class</i>.&nbsp;
    Triggers a compile-time error if it's inconsistent with other declarations
    or uses of the expression.&nbsp; For example, you can't say <code>(+ 1 (the
    void (- 4 7)))</code>, since <code>void</code> isn't a numeric type.
    <ul>
      <li>Note the compiler may still decide that <i>object </i>is of some
        subtype of <i>type</i>.&nbsp; For example, in:<br>
        <code>&nbsp;&nbsp;&nbsp;&nbsp; (let ((x (the float 0)))<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (vector-ref v x))</code><br>
        the compiler will generate C# code that declares x to be an integer, not
        a float, since <code>vector-ref</code> requires its argument to be an
        integer.</li>
    </ul>
  </li>
  <li><code>(cast </code><i>type object</i><code>)</code><br>
    A run-time operation to change <i>object</i> to <i>type</i>.&nbsp; Triggers
    a run-time error if it's impossible.</li>
  <li><code>(new </code><i>type arguments</i> ...<code>)</code><br>
    The C# new operator.</li>
  <li><code>(new-array </code><i>type length initial-values</i> ...<code>)</code><br>
    The C# new operator for arrays.&nbsp; Initial values are optional.</li>
  <li><code>(throw </code><i>exception</i><code>)</code><br>
    Throws an exception.&nbsp; Sorry, no catch yet.</li>
</ul>
<p>For the rest, consult the file <code>standard-environment.scm</code> to see
what's been imported into the environment.</p>
<h2>Built-in data types</h2>
<p>The macro language supports the following core data types:</p>
<ul>
  <li>Value types <code>integer</code>, <code>boolean</code>, <code>float</code>,
    and <code>character</code>, which correspond to the C# types <code>int</code>,
    <code>bool</code>, <code>double</code>, and <code>char</code>,
    respectively.&nbsp; Note that <code>int</code> in C# is called <code>int32</code>
    in the rest of .NET.&nbsp; Note that:
    <ul>
      <li>.NET and C# don't allow subtyping of value types.&nbsp; For purposes
        of type inference, the macro processor pretends the number types form a lattice, i.e.
        that <code>integer</code> is a &quot;subclass&quot; of <code>float</code>.</li>
    </ul>
  </li>
  <li>The singleton type <code>void</code>.</li>
  <li>The class types <code>object</code> and <code>string</code>.</li>
  <li>The type operator <code>array</code>, i.e. <code>(array object)</code>
    corresponds to the C# data type <code>Object[]</code>.</li>
</ul>
<p>There are also a bunch of data types that are <b>not </b>supported:</p>
<ul>
  <li>There is no procedure data type because C# and .NET aren't procedural
    languages, although the type inference system pretends that things that look
    like procedures have procedural types.&nbsp; Thus, the type inference system
    thinks + is a procedure with a procedural type when it's really an
    overloaded method.</li>
  <li>There is no pair or list data type.&nbsp; Use arrays or array-lists.</li>
</ul>
<h2>Calling native code</h2>
<p>You can call code in the .NET class library, but you have to enter the type
declarations for the classes you're calling manually (sorry).&nbsp; You use the <code>define-imported-class</code>
macro, which behaves pretty much like <code>define-class</code> except that you
don't include bodies or initial values for the member declarations and you only
define those members that are actually introduced by the class (you don't need
to tell it about overridden members).&nbsp; You also only need to tell it about
those members you actually use.&nbsp; The two annoying differences between it
and a normal define-class form are that (1) you put the return type and field
types in a different place and (2) it's a <b>scheme macro</b>, not macro 
language code per
se.&nbsp; So you don't put it inside your normal program.</p>
<blockquote>
  <p><code>(define-imported-class (</code><i>name&nbsp; .NETName </i><code>(</code><i>type
  constructor-arg</i><code>) </code>...<code>) </code><i>parent<br>
  </i><code>&nbsp; (define </code><i>field<code> </code></i><code>(</code><i>keywords
  </i>...<code>)</code>&nbsp; <i>type</i><code>)</code> ...<br>
  <code>&nbsp; (define (</code><i>method&nbsp; thisarg</i><code>&nbsp; (</code><i>type
  arg</i><code>) </code>...<code>) (</code><i>keywords</i> ...<code>)</code><i>&nbsp;
  return-type</i><code>) </code>...<code>)</code></p>
</blockquote>
<p>Notes:</p>
<ul>
  <li>The <i>.NETName</i> field is optional.&nbsp; It gives you the flexibility
    to define the macro language name and the native .NET name differently.</li>
  <li>Again, if the constructor arguments and parentheses are omitted, it's
    assumed that the class is abstract</li>
  <li>The type field isn't included in the same list with the keywords.&nbsp;
    That's partly because it's a little more legible that way and partly because
    the scheme macro system can't parse the syntax used in the normal macro 
	language
    code.&nbsp; Sorry.</li>
</ul>
<h2>Macros</h2>
<p>Macros are a bit of a kluge implemented at the level of the parser.&nbsp;
Like import declarations, they are defined with a <i>scheme-level </i>macro, so
their definitions can't be embedded in your normal code.&nbsp; They are Common
Lisp style macros, in the sense that (1) they don't have the built-in Scheme
pattern matching (2) they're &quot;non-hygienic&quot;, i.e. you have to be
careful about shadowing variable names, and (3) they're expected to return a
list, generally created, using backquote, that will then be run through the
normal parser.</p>
<blockquote>
  <p><code>(define-macro (</code><i>name&nbsp; args </i>...<code>)<br>
  &nbsp; `(</code>...<i> code </i>....<code>))</code></p>
</blockquote>
<p>However, they don't support Common Lisp fancy structured argument lists
either, so if you want to destructure your argument lists, then you have to
parse them manually.&nbsp; So for example, the <code>dotimes</code> macro, has
the format (dotimes (n count) body ...), has to be defined as:</p>
<blockquote>
  <p><code>(define-macro (<b>dotimes </b>var/limit . body)<br>
  &nbsp; (let ((var (car var/limit))<br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (limit (cadr var/limit)))<br>
  &nbsp;&nbsp;&nbsp; `(do ((,var 0 (+ ,var 1)))<br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (&lt; ,var ,limit)<br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ,@body)))</code></p>
</blockquote>

</body>

</html>
